/*================================================================
 *   Copyright (C) 2021 All rights reserved.
 *   
 *   文件名称：log.h
 *   创 建 者：汉森伯逸
 *   创建日期：2021年02月22日
 *   描    述：
 *
 *================================================================*/
#pragma once

#include <locale>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <fstream>
#include <sstream>
#include <list>
#include <yaml-cpp/node/node.h>
#include "util/util.h"
#include "singleton.h"
#include "thread.h"

#define HSBY_LOG_ROOT() hsby::LoggerManagerSgt::Instance().getRoot()
#define HSBY_LOG_NAME(name) hsby::LoggerManagerSgt::Instance().getLogger(name)

#define HSBY_LOG_LEVEL(logger, level)   \
    if (logger->getLevel() <= level)         \
        hsby::LogEventWrap(level,       \
                           hsby::LogEvent::Ptr(new hsby::LogEvent(logger, level, \
                           __FILE__,    \
                           __LINE__,    \
                           0,\
                           hsby::GetThisThreadId(),                           \
                           hsby::GetThisThreadName(),   \
                           hsby::GetThisFiberIntId(),                            \
                           time(0)))).getSS()

#define HSBY_LOG_DEBUG(logger) HSBY_LOG_LEVEL(logger, hsby::LogLevel::DEBUG)
#define HSBY_LOG_INFO(logger) HSBY_LOG_LEVEL(logger, hsby::LogLevel::INFO)
#define HSBY_LOG_WARN(logger) HSBY_LOG_LEVEL(logger, hsby::LogLevel::WARN)
#define HSBY_LOG_ERROR(logger) HSBY_LOG_LEVEL(logger, hsby::LogLevel::ERROR)
#define HSBY_LOG_FATAL(logger) HSBY_LOG_LEVEL(logger, hsby::LogLevel::FATAL)

/*
 * @brief 定义方便使用的宏
 */
/*
#define HSBY_LOG_FMT_LEVEL(logger, level, fmt, ...)   \
    if (logger->getLevel() <= level)         \
        hsby::LogEventWrap(level,                     \
                           hsby::LogEvent::Ptr(new hsby::LogEvent(logger, level, \
                           __FILE__,                  \
                           __LINE__,                  \
                           0, \
                           hsby::GetThisThreadId(),\
                           hsby::GetThisThreadName(),  \
                           hsby::GetThisFiberIntId(), \
                           time(0)))).getEvent()->Format(fmt, __VA_ARGS__)

#define HSBY_LOG_FMT_DEBUG(logger, fmt, ...) HSBY_LOG_FMT_LEVEL(logger, hsby::LogLevel::DEBUG, fmt, __VA_ARGS__)
#define HSBY_LOG_FMT_INFO(logger, fmt, ...) HSBY_LOG_FMT_LEVEL(logger, hsby::LogLevel::INFO, fmt, __VA_ARGS__)
#define HSBY_LOG_FMT_WARN(logger, fmt, ...) HSBY_LOG_FMT_LEVEL(logger, hsby::LogLevel::WARN, fmt, __VA_ARGS__)
#define HSBY_LOG_FMT_ERROR(logger, fmt, ...) HSBY_LOG_FMT_LEVEL(logger, hsby::LogLevel::ERROR, fmt, __VA_ARGS__)
#define HSBY_LOG_FMT_FATAL(logger, fmt, ...) HSBY_LOG_FMT_LEVEL(logger, hsby::LogLevel::FATAL, fmt, __VA_ARGS__)
*/

namespace hsby {

class Logger;
class LoggerManager;

/*
 * @brief 日志级别
 */
class LogLevel {
public:
    enum Level {
        UNKNOW = 0,
        DEBUG = 1,
        INFO  = 2,
        WARN  = 3,
        ERROR = 4,
        FATAL = 5
    };
    static const char* ToString(LogLevel::Level level);
    static Level ParseFromString(std::string str);
};


/*
 * @brief 日志事件
 */
class LogEvent {
public:
    typedef std::shared_ptr<LogEvent> Ptr;

    /**
     * @brief 构造函数
     */
    LogEvent(
            std::shared_ptr<Logger>,
            LogLevel::Level,
            const char *,
            int32_t,
            uint32_t,
            uint32_t,
            const std::string&,
            uint32_t,
            uint64_t
    );

    /**
     * @brief 获取文件名
     */
    const char* getFile() const  { return m_file; }

    /**
     * @brief 获取行号
     */
    int32_t     getLine() const  { return m_line; }

    /**
     * @brief 获取程序运行时长
     */
    uint32_t    getElapse() const  { return m_elapse; }

    /**
     * @brief 获取线程id
     */
    uint32_t    getThreadId() const  { return m_threadId; }

    /**
     * @brief 获取线程名字
     */
    std::string getThreadName() const  {return m_threadName;}

    /**
     * @brief 获取协程id
     */
    uint32_t    getFiberId() const  { return m_fiberID; }

    /**
     * @brief 获取时间
     */
    uint32_t    getTime() const  { return m_time; }

    /**
     * @brief 获取内容
     */
    std::string getContent() const  { return m_ss.str(); }

    /**
     * @brief 获取字符串输出流
     */
    std::stringstream& getSS()  { return m_ss;}

    /**
     * @brief 获取日志器
     */
    const std::shared_ptr<Logger> &getLogger() const { return m_logger; }

    /**
     * @brief 获取日志级别
     */
    LogLevel::Level getLevel() const  { return m_level; }

    /**
     * @brief 格式化
     */
    void format(const char* fmt, ...);

    /**
     * @brief 格式化
     */
    void format(const char* fmt, va_list al);

private:
    const char *                m_file          = nullptr;  // 文件名
    std::shared_ptr<Logger>     m_logger        = nullptr;  // 日志器
    int32_t                     m_line          = 0;        // 行号
    uint32_t                    m_elapse        = 0;        // 程序启动到现在的毫秒数
    uint32_t                    m_threadId      = 0;        // 线程Id
    std::string                 m_threadName    = 0;        // 线程Name
    uint32_t                    m_fiberID       = 0;        // 协程Id
    uint64_t                    m_time          = 0;        // 时间
    std::stringstream           m_ss;                       // 内容
    LogLevel::Level             m_level;                    // 日志级别
};


/**
 * @brief 日志交换, 用于支持流式输出日志
 */
class LogEventWrap {
public:
    LogEventWrap(LogLevel::Level , const LogEvent::Ptr &event);
    virtual ~LogEventWrap();

    /*
     * @brief 获取日志事件
     */
    const LogEvent::Ptr &getEvent() const;

    /*
     * @brief 获取事件中的日志内容流
     */
    std::stringstream& getSS();

private:
    LogLevel::Level m_level;
    LogEvent::Ptr m_event;
};


/**
 * @brief 日志格式化器
 */
class LogFormatter {
public:
    typedef std::shared_ptr<LogFormatter> Ptr;

public:
    LogFormatter(const std::string&);

public:
    /**
     * @brief 格式化日志为字符串
     * @param[in] logger 日志器
     * @param[in] level 日志等级
     * @param[in] event 日志事件
     * @return 日志字符串
     */
    std::string format(std::shared_ptr<Logger>, LogLevel::Level level, LogEvent::Ptr event);

    /**
     * @brief 格式化日志到输出流
     * @param[out] os 输出流
     * @param[in] logger 日志器
     * @param[in] level 日志等级
     * @param[in] event 日志事件
     */
    std::ostream& format(std::ostream& os, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::Ptr event) ;
    void init();

    /**
     * @brief 获取模式
     */
    std::string getPattern() { return m_pattern;}

    /**
     * @brief 设置模式
     */
    void setPattern(std::string pattern)  {m_pattern = pattern;}

public:
    /*
     * @brief 用于解析pattern的条目, 每个条目都通过format返回解析内容
     */
    class FormatItem {
    public:
        typedef std::shared_ptr<FormatItem> Ptr;
        virtual ~FormatItem() {}
        virtual void Format(std::shared_ptr<Logger> logger, std::ostream& os, LogLevel::Level level, LogEvent::Ptr event) = 0;
    };
    FormatItem::Ptr GetFormatItem(const std::string&, const std::string&, const std::string& ) ;

private:
    /*
     * @brief
     */
    std::string                     m_pattern;
    std::vector<FormatItem::Ptr>    m_items;
};

/*
 * @brief 日志输出地
 */
class LogAppender {
public:
    typedef std::shared_ptr<LogAppender> Ptr;
    typedef RWMutex MutexType;

public:
    virtual ~LogAppender() {}

public:
    /**
     * @brief 处理日志
     * @param[in] logger 日志器
     * @param[in] level 日志等级
     * @param[in] event 日志事件
     */
    virtual void Log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::Ptr event) = 0;
    
    /**
     * @brief 将本对象输出为yaml对象
     * @return yaml对象
     */
    virtual YAML::Node toYaml() = 0;

    /**
     * @brief 设置日志等级
     * @param[in] level 日志等级
     */
    void setLevel(LogLevel::Level level)  {
        m_level = level;
    }

    /*
     * @brief 设置format
     */
    void setFormatter(LogFormatter::Ptr formatter);
    LogFormatter::Ptr getFormatter();

    /*
     * @brief 设置defaultFormat
     */
    void setDefaultFormatter(LogFormatter::Ptr formatter);
    LogFormatter::Ptr getDefaultFormatter();


    /**
     * @brief  返回是否拥有自己的格式化器
     * @return bool
     */
    bool hasFormatter();

protected:
    LogLevel::Level     m_level;
    LogFormatter::Ptr   m_formatter;
    LogFormatter::Ptr   m_defaultFormatter;
    MutexType m_mutex;
};


/*
 * @brief 日志器
 */
class Logger : public std::enable_shared_from_this<Logger> {
friend class LoggerManager;

public:
    typedef std::shared_ptr<Logger> Ptr;
    typedef RWMutex MutexType;

public:
    Logger(const std::string& name);

public:
    void Log(LogLevel::Level level, LogEvent::Ptr event);

    /**
     * @brief 获取日志器名字
     */
    std::string getName() { return m_name; }

    /**
     * @brief 添加Appenders
     */
    void addAppender(LogAppender::Ptr appender);

    /**
     * @brief 删除Appenders
     */
    void delAppender(LogAppender::Ptr appender);

    /**
     * @brief 清理Appenders
     */
    void clearAppender();

    /**
     * @brief 设置格式化器
     * @param[in] formatter 格式化器
     */
    void setFormatter(LogFormatter::Ptr formatter);

    /**
     * @brief 设置格式化器
     * @param[in] format 格式化模式
     */
    void setFormatter(std::string format);
    LogFormatter::Ptr getFormatter() { return m_default_formatter;}

    /*
     * @brief 获取日志等级
     */
    LogLevel::Level getLevel() const  {return m_level;};

    /**
     * @brief 设置日志等级
     */
    void setLevel(LogLevel::Level level) {m_level = level;};

    /**
     * @brief 输出本对象为yaml对象
     * @return yaml对象
     */
    YAML::Node toYaml();

private:
    std::string                 m_name;             // 日志名称
    LogLevel::Level             m_level;            // 日志级别, 默认限制为DEBUG
    MutexType                   rw_mutex_;          // 互斥锁
    std::list<LogAppender::Ptr> m_appenders;        // 输出地集合
    LogFormatter::Ptr           m_default_formatter;// 默认格式器
    Logger::Ptr                 m_root_logger;      // 根日志器
    std::vector<LogEvent::Ptr>  event_buffer;       // 日志缓存
};

// 控制台Appender
class StdoutLogAppender : public LogAppender {

public:
    typedef std::shared_ptr<StdoutLogAppender> Ptr;

    /**
     * @brief 输出日志
     * @param[in] logger 日志器
     * @param[in] level 日志级别
     * @param[in] event 日志事件
     */
    void Log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::Ptr event) override;

    /**
     * @brief 将对象输出为yaml对象
     */
    YAML::Node toYaml() override;

private:

};

// 文件Appender
class FileLogAppender : public LogAppender {
public:
    typedef std::shared_ptr<FileLogAppender> Ptr;

public:
    FileLogAppender(const std::string );

public:
    /**
     * @brief 输出日志
     * @param[in] logger 日志器
     * @param[in] level 日志级别
     * @param[in] event 日志事件
     */
    void Log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::Ptr event) override;

    /**
     * @brief 重新打开文件
     */
    bool reopen();

    /**
     * @brief 将对象输出为yaml对象
     */
    YAML::Node toYaml() override;

private:
    std::string     m_filename = "hsby_default_log.txt";
    std::ofstream   m_filestream;
};

/*
 * @brief 日志器管理器
 */
class LoggerManager {
public:
    typedef Mutex MutexType;

public:
    LoggerManager();

    /**
     * @brief 获取日志器
     * @param[in] 名字
     * @return 日志器
     */
    Logger::Ptr getLogger(const std::string& name);

    /**
     * @brief 获取根日志器
     * @return 日志器
     */
    Logger::Ptr getRoot() const  {
        return m_root;
    };

    /**
     * @brief 将对象转换为yaml对象
     * @param[in]
     * @return
     */
    YAML::Node toYaml();

    /**
     * @brief 初始化
     */
    void init();

private:
    MutexType m_mutex;
    std::map<std::string, Logger::Ptr>  m_loggers;
    Logger::Ptr                         m_root;
};
using LoggerManagerSgt = hsby::Singleton<LoggerManager>;

} // namespace hsby

static auto g_system_logger = HSBY_LOG_NAME("system");
#define HSBY_LOG_SYSTEM_DEBUG HSBY_LOG_DEBUG(g_system_logger)
#define HSBY_LOG_SYSTEM_INFO  HSBY_LOG_INFO(g_system_logger)
#define HSBY_LOG_SYSTEM_WARN  HSBY_LOG_WARN(g_system_logger)
#define HSBY_LOG_SYSTEM_ERROR HSBY_LOG_ERROR(g_system_logger)
#define HSBY_LOG_SYSTEM_FATAL HSBY_LOG_FATAL(g_system_logger)